package org.person.gift.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.person.gift.doc.GiftSpuDoc;
import org.person.gift.query.QueryResult;
import org.person.gift.search.GiftSpuSearch;
import org.person.gift.service.IGiftSpuSearchService;
import org.person.gift.util.HighlightResultMapper;
import org.person.gift.util.SearchUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
public class GiftSpuSearchServiceImpl implements IGiftSpuSearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HighlightResultMapper resultMapper;


    @Override
    public QueryResult<GiftSpuDoc> search(GiftSpuSearch search) {
        //建立查询对象
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //==========添加筛选条件==========
        //1.关键字查询 keyWord -> title,carInfo,shopName,typeName
        String keyWord = search.getKeyword();
        if (StringUtils.isNotBlank(keyWord)){
            List<QueryBuilder> must = boolQuery.must();
            must.add(QueryBuilders.multiMatchQuery(keyWord,
                    "goodsName","tenantName","categoryName","branName","specProperties","skuProperties"
            ));
        }

        //2.价格范围查询  minPrice <= costprice <maxPrice
        List<QueryBuilder> filter = boolQuery.filter();
        if (Objects.nonNull(search.getMaxPrice())) {
            filter.add(QueryBuilders.rangeQuery("highPrice").lt(search.getMaxPrice()));
        }
        if (Objects.nonNull(search.getMinPrice())) {
            filter.add(QueryBuilders.rangeQuery("lowPrice").gte(search.getMinPrice()));
        }
        //等值条件晒选   传入类型ID和商家ID
        if(Objects.nonNull(search.getCategoryId())){
            filter.add(QueryBuilders.termQuery("categoryId",search.getCategoryId()));
        }
        if(Objects.nonNull(search.getTenantId())){
            filter.add(QueryBuilders.termQuery("tenantId",search.getTenantId()));
        }

        //==========添加排序条件===============
        //默认售价排序
        String sortField = search.getSortField();
        if(StringUtils.isBlank(sortField)){
            sortField = "onsaletime";
        }
        String sortType = search.getSortType();
        //默认排序方式为降序
        SortOrder sortOrder = "asc".equals(sortType)?SortOrder.ASC:SortOrder.DESC;
        FieldSortBuilder order = SortBuilders.fieldSort(sortField).order(sortOrder);
        //排序规则赋给queryBuilder
        queryBuilder.withSort(order);

        //==========添加分页条件，规定每页十二条内容==========
        //es中语法from是计算从那一条数据开始，计算公式为（当前页数-1）*每页数量
        PageRequest page = PageRequest.of(search.getPage() - 1, search.getRows());
        queryBuilder.withPageable(page);

        //高亮展示
        //添加需要高亮显示的字段,一般分词查询的才需要高亮展示
        //"goodsName","tenantName","categoryName","branName","specProperties","skuProperties"
        HighlightBuilder.Field field1 = new HighlightBuilder.Field("goodsName")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        HighlightBuilder.Field field2 = new HighlightBuilder.Field("tenantName")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        HighlightBuilder.Field field3 = new HighlightBuilder.Field("categoryName")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        HighlightBuilder.Field field4 = new HighlightBuilder.Field("branName")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        HighlightBuilder.Field field5 = new HighlightBuilder.Field("specProperties")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        HighlightBuilder.Field field6 = new HighlightBuilder.Field("specProperties")
                .preTags("<span style='color:red;font-weight:bold'>").postTags("</span>");
        queryBuilder.withHighlightFields(field1,field2,field3,field4,field5,field6);

        //聚合查询。根据车辆类型的id和name进行分组，还有根据店铺的id和类型进行分组，实现按照特定字段内容同词分组查询统计每组有多少数据
        //根据车辆类型id聚合查询，再内嵌根据类型名字子聚合
        TermsAggregationBuilder typeNameTerm = AggregationBuilders.terms("typeNameTerm").field("typeName.keyword").order(BucketOrder.count(false));
        TermsAggregationBuilder typeIdTerm = AggregationBuilders.terms("typeIdTerm").field("typeId").order(BucketOrder.count(false))
                .subAggregation(typeNameTerm);
        //根据店铺id聚合查询，再内嵌根据店铺名字子聚合
        TermsAggregationBuilder shopNameTerm = AggregationBuilders.terms("shopNameTerm").field("shopName.keyword").order(BucketOrder.count(false));
        TermsAggregationBuilder shopIdTerm = AggregationBuilders.terms("shopIdTerm").field("shopId").order(BucketOrder.count(false))
                .subAggregation(shopNameTerm);
        queryBuilder.addAggregation(typeIdTerm);
        queryBuilder.addAggregation(shopIdTerm);

        //通过查询对象从repository中获取存储在Es服务器的内容
//        Page<CarDoc> searchResult = repository.search(queryBuilder.build());
        //对于自定义结果映射repository是不能查询结果的
        AggregatedPage<GiftSpuDoc> searchResult = elasticsearchTemplate.queryForPage(queryBuilder.build(), GiftSpuDoc.class, resultMapper);
        //聚合结果
        Aggregations aggregations = searchResult.getAggregations();
        Map<String, Object> aggsData = SearchUtil.handleTermsAggsData(aggregations);

        //获取查询结果中的总条数和数据集合
        Long total = searchResult.getTotalElements();
        List<GiftSpuDoc> list = searchResult.getContent();
        //为返回结果封装对象进行赋值
//        QueryResult<CarDoc> queryResult = new QueryResult<>();
//        queryResult.setTotal(total);
//        queryResult.setDataList(list);
        //返回封装结果
        return new QueryResult<GiftSpuDoc>(total,list,aggsData);
    }
}
